using System;
using System.Collections;
using System.Globalization;
using System.Reflection;
using System.Resources;
using EnvDTE;
using Microsoft.VisualStudio.CommandBars;
using NUnitGenAddIn.Core;

namespace NUnitGenAddIn.VS2008
{
    /// <summary>
    /// VS2008 Add-In Helper
    /// </summary>
    public class VS2008AddInHelper : AddInHelper
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="VS2008AddInHelper"/> class.
        /// </summary>
        /// <param name="applicationObject">The application object.</param>
        /// <param name="addInInstance">The add in instance.</param>
        public VS2008AddInHelper(DTE applicationObject, AddIn addInInstance) : base(applicationObject, addInInstance)
        {}
        
        /// <summary>
        /// Gets the code element list from point.
        /// </summary>
        /// <param name="currentPoint">The current point.</param>
        /// <returns>Array List</returns>
        public override ArrayList GetCodeElementListFromPoint(TextPoint currentPoint)
        {
            ArrayList codeElements = new ArrayList();
            FileCodeModel fileCodeModel = GetCodeModel4CurrentProjectItem();

            if (fileCodeModel != null)
            {
                foreach (vsCMElement scope in Enum.GetValues(typeof (vsCMElement)))
                {
                    CodeElement codeElement = null;
                    try
                    {
                        codeElement = fileCodeModel.CodeElementFromPoint(currentPoint, scope);
                    }
                    catch
                    {}

                    if (codeElement != null)
                        codeElements.Add(codeElement);
                }
            }
            return codeElements;
        }

        /// <summary>
        /// Gets the code class from code elements.
        /// </summary>
        /// <param name="codeElements">The code elements.</param>
        /// <returns><see cref="CodeClass"/> object</returns>
        public override CodeClass GetCodeClassFromCodeElements(CodeElements codeElements)
        {
            foreach (CodeElement element in codeElements)
            {
                if (element.Kind == vsCMElement.vsCMElementClass)
                {
                    return element as CodeClass;
                }
                
                if (element.Children.Count > 0)
                {
                    CodeClass returnedElement = GetCodeClassFromCodeElements(element.Children);
                    if (returnedElement != null)
                        return returnedElement;
                }
            }
            return null;
        }

        /// <summary>
        /// Adds the command.
        /// </summary>
        /// <param name="commandName">Name of the command.</param>
        /// <param name="buttonText">The button text.</param>
        /// <param name="toolTip">The tool tip.</param>
        /// <param name="commandBarName">Name of the command bar.</param>
        protected override void AddCommand(string commandName, string buttonText, string toolTip, string commandBarName)
        {
            CommandBar commandBar = getTargetCommandBar(commandBarName);
            try
            {
                object[] contextGuids = new object[] {};
                //Add a command to the Commands collection:
                Command command =
                    _applicationObject.Commands.AddNamedCommand(_addInInstance, commandName, buttonText, toolTip, true, 59,
                                                               ref contextGuids,
                                                               (int) vsCommandStatus.vsCommandStatusSupported +
                                                               (int) vsCommandStatus.vsCommandStatusEnabled);
                //, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton);
                if (commandBar != null)
                    command.AddControl(commandBar, 2);
            }
            catch (Exception)
            {
            }
        }

        /// <summary>
        /// Gets the target command bar.
        /// </summary>
        /// <param name="commandBarName">Name of the command bar.</param>
        /// <returns><see cref="CommandBar"/> object</returns>
        private CommandBar getTargetCommandBar(string commandBarName)
        {
            return getTargetCommandBar(commandBarName, "");
        }

        /// <summary>
        /// Gets the target command bar.
        /// </summary>
        /// <param name="commandBarName">Name of the command bar.</param>
        /// <param name="subMenuName">Name of the sub menu.</param>
        /// <returns><see cref="CommandBar"/> object</returns>
        private CommandBar getTargetCommandBar(string commandBarName, string subMenuName)
        {
            //Place the command on the tools menu.
            //Find the MenuBar command bar, which is the top-level command bar holding all the main menu items:
            CommandBar menuBarCommandBar = ((CommandBars) _applicationObject.CommandBars)[commandBarName];
            CommandBar targetCommandBar = menuBarCommandBar;

            if (!string.IsNullOrEmpty(subMenuName))
            {
                //Find the Tools command bar on the MenuBar command bar:
                CommandBarControl toolsControl = menuBarCommandBar.Controls[getLocalizedMenuName(subMenuName)];
                CommandBarPopup toolsPopup = (CommandBarPopup) toolsControl;
                targetCommandBar = toolsPopup.CommandBar;
            }
            return targetCommandBar;
        }

        /// <summary>
        /// Gets the name of the localized menu.
        /// </summary>
        /// <param name="menuName">Name of the menu.</param>
        /// <returns>string value</returns>
        private string getLocalizedMenuName(string menuName)
        {
            string toolsMenuName;
            try
            {
                //If you would like to move the command to a different menu, change the word "Tools" to the 
                //  English version of the menu. This code will take the culture, append on the name of the menu
                //  then add the command to that menu. You can find a list of all the top-level menus in the file
                //  CommandBar.resx.
                ResourceManager resourceManager =
                    new ResourceManager(_addInInstance.ProgID + ".CommandBar", Assembly.GetExecutingAssembly());
                CultureInfo cultureInfo = new CultureInfo(_applicationObject.LocaleID);

                toolsMenuName = resourceManager.GetString(String.Concat(cultureInfo.TwoLetterISOLanguageName, menuName));
            }
            catch
            {
                //We tried to find a localized version of the word Tools, but one was not found.
                //  Default to the en-US word, which may work for the current culture.
                toolsMenuName = "Tools";
            }
            return toolsMenuName;
        }
    }
}